#include <stdint.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "module.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <sys/select.h>
#include "autoconfig.h"
#include "sys/err.h"
#include "apitrans.h"

sys_apitrans_t sysapi;

int asc2bcd(char * ascstr, int len, uint8_t *bcdstr, int align)
{
    int ( *pasc2bcd)(char * ascstr, int len, uint8_t *bcdstr, int align);
    pasc2bcd = sysapi(ASC2BCD_API);
    if (pasc2bcd) {
        return pasc2bcd(ascstr, len, bcdstr, align);
    }
    return -API_UNSUPPORTED_ERR;
}
int bcd2asc(uint8_t * bcd, int asclen, char * asc, int align)
{
    int (*pbcd2asc)(uint8_t * bcd, int asclen, char * asc, int align);
    pbcd2asc = sysapi(BCD2ASC_API);
    if (pbcd2asc) {
        return pbcd2asc(bcd, asclen, asc, align);
    }
    return -API_UNSUPPORTED_ERR;
}
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
    int (*pgettimeofday)(struct timeval *tv, struct timezone *tz);
    pgettimeofday = sysapi(GETTIMEOFDAY_API);
    if (pgettimeofday) {
        return pgettimeofday(tv, tz);
    }
    return -API_UNSUPPORTED_ERR;
}
int settimeofday(const struct timeval *tv , const struct timezone *tz)
{
    int (*psettimeofday)(const struct timeval *tv , const struct timezone *tz);
    psettimeofday = sysapi(SETTIMEOFDAY_API);
    if (psettimeofday) {
        return psettimeofday(tv, tz);
    }
    return -API_UNSUPPORTED_ERR;
}


int open(const char *pathname, int oflag, ... /* mode_t mode */)
{
  int (*popen)(const char *pathname, int oflag, ... /* mode_t mode */);
  popen = sysapi(OPEN_API);
  if (popen) {
      return popen(pathname, oflag);
  }
  return -API_UNSUPPORTED_ERR;
}

int close(int fd)
{
    int (*pclose)(int fd);
    pclose = sysapi(CLOSE_API);
    if (pclose) {
        return pclose(fd);
    }
    return -API_UNSUPPORTED_ERR;

}

ssize_t read(int fd, void * buffer, size_t len)
{
    ssize_t (*pread)(int fd, void * buffer, size_t len);
    pread = sysapi(READ_API);
    if (pread) {
        return pread(fd, buffer, len);
    }
    return -API_UNSUPPORTED_ERR;
}

ssize_t write(int fd, const void * buffer, size_t len)
{
    ssize_t (*pwrite)(int fd, const void * buffer, size_t len);
    pwrite = sysapi(WRITE_API);
    if (pwrite) {
        return pwrite(fd, buffer, len);
    }
    return -API_UNSUPPORTED_ERR;

}

int select(int nfds, fd_set *readfds, fd_set *writefds,
                   fd_set *exceptfds, struct timeval *timeout)
{
    int (*pselect)(int nfds, fd_set *readfds, fd_set *writefds,
                       fd_set *exceptfds, struct timeval *timeout);
    pselect = sysapi(SELECT_API);
    if (pselect) {
        return pselect(nfds, readfds, writefds, exceptfds, timeout);
    }
    return -API_UNSUPPORTED_ERR;
}
int unlink(const char * pathname)
{
    int (*punlink)(const char * pathname);
    punlink = sysapi(UNLINK_API);
    if (punlink) {
        return punlink(pathname);
    }
    return -API_UNSUPPORTED_ERR;
}

int ioctl(int fd, int cmd, void *arg)
{
    int (*pioctl)(int fd, int cmd, void *arg);
    
    pioctl = sysapi(IOCTL_API);
    if (pioctl) {
        return pioctl(fd, cmd, arg);
    }
    return -API_UNSUPPORTED_ERR;

}

off_t lseek(int fd, off_t offset, int whence)
{
    off_t (*lseek)(int fd, off_t offset, int whence);
    
    lseek = sysapi(LSEEK_API);
    if (lseek) {
        return lseek(fd, offset, whence);
    }
    return -API_UNSUPPORTED_ERR;


}
int truncate(int fd, off_t lenght)
{
    int (*ptruncate)(int fd, off_t lenght);
    
    ptruncate = sysapi(TRUNCATE_API);
    if (ptruncate) {
        return ptruncate(fd, lenght);
    }
    return -API_UNSUPPORTED_ERR;

}


int kb_get_key(int ms)
{
    int (*pkb_get_key)(int ms);
    pkb_get_key = sysapi(KB_GET_KEY_API);
    if (pkb_get_key) {
        return pkb_get_key(ms);
    }   
    return -API_UNSUPPORTED_ERR;
}


int serial_init(uint32_t id, serial_info_t * info)
{
    int (*pserial_init)(uint32_t id, serial_info_t * info);
    pserial_init = sysapi(SERIAL_INIT_API);
    if (pserial_init) {
        return pserial_init(id, info);
    }   
    return -API_UNSUPPORTED_ERR;
}
int serial_write(uint32_t id, uint8_t * buffer, size_t len)
{
    int (*pserial_write)(uint32_t id, uint8_t * buffer, size_t len);
    pserial_write = sysapi(SERIAL_WRITE_API);
    if (pserial_write) {
        return pserial_write(id, buffer, len);
    }   
    return -API_UNSUPPORTED_ERR;
}

int serial_read(uint32_t id, uint8_t * buffer, size_t len, int timeout)
{
    int (*pserial_read)(uint32_t id, uint8_t * buffer, size_t len, int timeout);
    pserial_read = sysapi(SERIAL_READ_API);
    if (pserial_read) {
        return pserial_read(id, buffer, len, timeout);
    }   
    return -API_UNSUPPORTED_ERR;
}

int serial_clrbuf(uint32_t id, int rx, int tx)
{
    int (*pserial_clrbuf)(uint32_t id, int rx, int tx);
    pserial_clrbuf = sysapi(SERIAL_CLRBUF_API);
    if (pserial_clrbuf) {
        return pserial_clrbuf(id, rx, tx);
    }   
    return -API_UNSUPPORTED_ERR;
}


void reset(void)
{
    void (*preset)(void);
    preset = sysapi(RESET_API);
    if (preset) {
        preset();
    }   
}

void mdelay(uint32_t ms)
{
    void (*pmdelay)(uint32_t ms);
    pmdelay = sysapi(MDELAY_API);
    if (pmdelay) {
        pmdelay(ms);
    }   
}

void buzzer_start(void)
{
    void (*pbuzzer_start)(void);
    pbuzzer_start = sysapi(BUZZER_START_API);
    if (pbuzzer_start) {
        pbuzzer_start();
    }   
}

void buzzer_stop(void)
{
    void (*pbuzzer_stop)(void);
    pbuzzer_stop = sysapi(BUZZER_STOP_API);
    if (pbuzzer_stop) {
        pbuzzer_stop();
    }   
}

void led_ctrl(uint32_t nr, uint32_t on)
{
    void (*pled_ctrl)(uint32_t nr, uint32_t on);
    pled_ctrl = sysapi(LED_CTRL_API);
    if (pled_ctrl) {
        pled_ctrl(nr, on);
    }   
}

uint32_t security_status(void)
{
    uint32_t (*psecurity_status)(void);
    psecurity_status = sysapi(SECURITY_STATUS_API);
    if (psecurity_status) {
        return psecurity_status();
    }   
    return -API_UNSUPPORTED_ERR;
}

int nv_write(uint32_t offset, uint8_t * buf, int buflen)
{
    int (*pnv_write)(uint32_t offset, uint8_t * buf, int buflen);
    pnv_write = sysapi(NV_WRITE_API);
    if (pnv_write) {
        return pnv_write(offset, buf, buflen);
    }   
    return -API_UNSUPPORTED_ERR;
}

int nv_read(uint32_t offset, uint8_t * buf, int buflen)
{
    int (*pnv_read)(uint32_t offset, uint8_t * buf, int buflen);
    pnv_read = sysapi(NV_READ_API);
    if (pnv_read) {
        return pnv_read(offset, buf, buflen);
    }   
    return -API_UNSUPPORTED_ERR;
}

int sys_get_param(uint32_t type, void *buf, uint32_t len)
{
    int (*psys_get_param)(uint32_t type, void *buf, uint32_t len);
    psys_get_param = sysapi(SYS_GET_PARAM_API);
    if (psys_get_param) {
        return psys_get_param(type, buf, len);
    }   
    return -API_UNSUPPORTED_ERR;
}

int sys_set_param(uint32_t type, void *buf, uint32_t len)
{
    int (*psys_set_param)(uint32_t type, void *buf, uint32_t len);
    psys_set_param = sysapi(SYS_SET_PARAM_API);
    if (psys_set_param) {
        return psys_set_param(type, buf, len);
    }   
    return -API_UNSUPPORTED_ERR;
}

void * sys_load_library(char *name)
{
    void * (*psys_load_library)(char *name);
    psys_load_library = sysapi(SYS_LOAD_LIBRARY_API);
    if (psys_load_library) {
        return psys_load_library(name);
    }   
    return -API_UNSUPPORTED_ERR;
}
 
int sys_run_app(char *name)
{
    int (*psys_run_app)(char *name);
    psys_run_app = sysapi(SYS_RUN_APP_API);
    if (psys_run_app) {
        return psys_run_app(name);
    }   
    return -API_UNSUPPORTED_ERR;
}

int sys_update_mod(mod_update_t *update, uint8_t nr)
{
    int (*psys_update_mod)(mod_update_t *update, uint8_t nr);
    psys_update_mod = sysapi(SYS_UPDATE_MOD_API);
    if (psys_update_mod) {
        return psys_update_mod(update, nr);
    }   
    return -API_UNSUPPORTED_ERR;
}

uint32_t timeout_start(void)
{
    uint32_t (*ptimeout_start)(void);
    ptimeout_start = sysapi(TIMEOUT_START_API);
    if (ptimeout_start) {
        return ptimeout_start();
    }   
    return -API_UNSUPPORTED_ERR;
}

uint32_t timeout_test(uint32_t *start, uint32_t *ms)
{
    uint32_t (*ptimeout_test)(uint32_t *start, uint32_t *ms);
    ptimeout_test = sysapi(TIMEOUT_TEST_API);
    if (ptimeout_test) {
        return ptimeout_test(start, ms);
    }   
    return -API_UNSUPPORTED_ERR;
}



int sys_sleep(int sleep, void *flush_func, int flush_time)
{
    int (*psys_sleep)(int sleep, void *flush_func, int flush_time);
    psys_sleep = sysapi(SYS_SLEEP_API);
    if (psys_sleep) {
        return psys_sleep(sleep, flush_func, flush_time);
    }   
    return -API_UNSUPPORTED_ERR;
}




void *malloc(int size)
{
    void *(*pmalloc)(int size);
    pmalloc = sysapi(MALLOC_API);
    if (pmalloc) {
        return pmalloc(size);
    }   
    return -API_UNSUPPORTED_ERR;
}
void *realloc(void *block, int size)
{
    void *(*prealloc)(void *block, int size);
    prealloc = sysapi(REALLOC_API);
    if (prealloc) {
        return prealloc(block, size);
    }   
    return -API_UNSUPPORTED_ERR;
}
int free(void * block)
{
    int (*pfree)(void * block);
    pfree = sysapi(FREE_API);
    if (pfree) {
        return pfree(block);
    }   
    return -API_UNSUPPORTED_ERR;
}

int pos_entry(pos_entry_t entry,pos_entry_un * data,int ms)
{
    int (*ppos_entry)(pos_entry_t entry, pos_entry_un * data,int ms);
    ppos_entry = sysapi(POS_ENTRY_API);
    if (ppos_entry) {
        return ppos_entry(entry, data, ms);
    }   
    return -API_UNSUPPORTED_ERR;

}


int default_fn(void){return 0;}
int appmod_init(void) __attribute__ ((weak, alias("default_fn")));
int module_init(sys_apitrans_t api)
{
        sysapi = api;
        return appmod_init();
}

int appmod_main(void) __attribute__ ((weak, alias("default_fn")));
void *appmod_export(void) __attribute__ ((weak, alias("default_fn")));


extern uint32_t _stext;
extern uint32_t _etext;
extern uint32_t _sdata;  /* start address for the .data section */
extern uint32_t _edata;  /* end address for the .data section */
extern uint32_t _sbss;       /* start address for the .bss section */
extern uint32_t _ebss;       /* end address for the .bss section */

static module_t appmod _module_header_entry = {
        .magic_num = MODULE_MAGIC,
        .text_start = (uint32_t)&_stext,
        .text_end = (uint32_t)&_etext,
        .data_start = (uint32_t)&_sdata,
        .data_end = (uint32_t)&_edata,
        .bss_start = (uint32_t)&_sbss,
        .bss_end = (uint32_t)&_ebss,
        .module_init = module_init,
        .module_main = appmod_main,
        .module_export = appmod_export,
};
